#ifndef CHART_H
#define CHART_H

#include <QtCore>
#include <QtCharts>

#include <optional>

class Chart: public QtCharts::QChart
{
    Q_OBJECT

public:
    static QValueAxis *getXAxis(QtCharts::QChart *chart);
    static QValueAxis *getYAxis(QtCharts::QChart *chart);

public:
    struct Range
    {
        qreal min, max;

        Range(qreal min, qreal max);
        inline void update(qreal val)
        {
            min = std::min(std::min(min, max), val);
            max = std::max(std::max(min, max), val);
        }
        inline bool is_valid() const
        {
            return min < max;
        }
    };

    struct Ranges
    {
        Range x, y;
        Ranges(qreal x_min, qreal x_max, qreal y_min, qreal y_max);
        inline bool is_valid() const
        {
            return x.is_valid() && y.is_valid();
        }
    };

    enum class Style
    {
          Line
        , Spline
        , Scatter
    };

    enum class Mode
    {
        Flexible
        , Fixed
    };

public:
    Chart();

public slots:
    void setUseOpenGL(bool use);

signals:
    void useOpenGLChanged(bool use);

public:
    void initFlexible(QString title);
    void initFixed(QString title, Ranges r);
    void setView(const Ranges &r);
    Mode mode();
    void replaceSeries(QString series_name, Style series_style = Style::Line);
    void addPoints(QString series_name, QVector<QPointF> points);
    void updateSeries();
    void fitBounds();

protected:
    bool event(QEvent *event) override;

private:
    struct SeriesBuffer
    {
        QXYSeries *series;
        bool is_need_update;
        QVector<QPointF> points;
    };
    struct ToAddSeries
    {
        Style style;
        QVector<QPointF> points;
    };

    Mode _mode;
    QHash<QString, SeriesBuffer> _serieses;
    std::optional<Ranges> _r;
    bool _use_opengl;

    void _reset(QString title, Ranges r);
};

#endif /* CHART_H */
